package com.fxu.framework.core.redis;

import cn.hutool.crypto.SecureUtil;
import com.fxu.framework.core.holder.RedisHolder;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 使用Redis来做Mybatis的二级缓存
 * 实现Mybatis的Cache接口
 * @author fangxu
 * @version 1.0.0
 */
public class MybatisRedis implements Cache {

	private static final Logger logger = LoggerFactory.getLogger(MybatisRedis.class);

	// 读写锁
	private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);

	private String id;

	public MybatisRedis(final String id) {
		if (id == null) {
			throw new IllegalArgumentException("Cache instances require an ID");
		}
		this.id = id;

		logger.debug("MybatisRedis id {}", this.id);
	}

	@Override
	public String getId() {
		return this.id;
	}

	@Override
	public int getSize() {
		try {
			return RedisHolder.getRedisTemplate().opsForHash().size(this.id).intValue();
		} catch (Exception e) {
			logger.error("getSize.error: id = {}, {}", id, e);
			return 0;
		}
	}

	@Override
	public void putObject(final Object key, final Object value) {
		String md5Key = SecureUtil.md5(key.toString());
		try {
			RedisHolder.getRedisTemplate().opsForHash().put(this.id, md5Key, value);
		} catch (Exception e) {
			logger.error("putObject.error: {}->{}->{}, {}", id, md5Key, key.toString().replace("\n", " "), e);
		}
	}

	@Override
	public Object getObject(final Object key) {
		String md5Key = SecureUtil.md5(key.toString());
		try {
			return RedisHolder.getRedisTemplate().opsForHash().get(this.id, md5Key);
		} catch (Exception e) {
			logger.error("getObject.error: {}->{}->{}, {}", id, md5Key, key.toString().replace("\n", " "), e);
			return null;
		}
	}

	@Override
	public Object removeObject(final Object key) {
		String md5Key = SecureUtil.md5(key.toString());
		try {
			RedisHolder.getRedisTemplate().opsForHash().delete(this.id, md5Key);
		} catch (Exception e) {
			logger.error("removeObject.error: {}->{}, {}", id, md5Key, e);
		}
		return null;
	}

	@Override
	public void clear() {
		try {
			RedisHolder.getRedisTemplate().delete(this.id);
		} catch (Exception e) {
			logger.error("clear.error: {}, {}", id, e);
		}
	}

	@Override
	public ReadWriteLock getReadWriteLock() {
		return this.readWriteLock;
	}
}
